package com.jt.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.jt.anno.CacheFind;
import com.jt.util.ObjectMapperUtil;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;

@Aspect
@Component
public class RedisAOP {
	/**
	 * 业务描述：
	 *     利用@CacheFind注解，实现redis缓存操作
	 *     1.动态生成key  包名.类名.方法名::第一个参数
	 *     2.利用redis查询数据
	 *     3.没数据     第一次查询数据库
	 *     4.有数据     查询缓存
	 * 技巧：
	 *     利用该配置，可以直接为参数添加指定的注解的对象。目的是为了将来获取
	 *     的属性方便
	 */
	@Autowired(required = false)
	//private ShardedJedis jedis;//redis分片
	//private Jedis jedis; //单台redis
	//private Jedis jedis; //redis哨兵
	private JedisCluster jedis;//redis的集群
	
	@Around("@annotation(cacheFind)")
	public Object around(ProceedingJoinPoint joinPonit,CacheFind cacheFind) throws Throwable {
		//1.动态生成key
		String key=getKey(joinPonit,cacheFind);
		//2.利用redis进行查询
		String json=jedis.get(key);
		Object returnObject=null;
		//3.判断redis中的数据是否有值
		if(StringUtils.isEmpty(json)) {
			try {
				returnObject=joinPonit.proceed();//执行目标方法，查询数据库
				String objJSON=ObjectMapperUtil.toJson(returnObject);
				if(cacheFind.seconds()>0) {
					//表示赋值的操作，有超时时间
					jedis.setex(key, cacheFind.seconds(), objJSON);
				}else {
					jedis.set(key, objJSON);
				}
				System.out.println("查询数据库");
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException();
			}
		}else {
			//redis中不为null，可以直接返回数据
			Class<?> targetClass=getClass(joinPonit);
			returnObject=ObjectMapperUtil.toObject(json, targetClass);
			System.out.println("查询缓存");
		}
		return returnObject;
	}
	//动态获取返回值类型
	private Class<?> getClass(ProceedingJoinPoint joinPonit) {
		MethodSignature methodSignature=(MethodSignature) joinPonit.getSignature();
		return methodSignature.getReturnType();
	}
	/**
	 * 如果用户有key，则使用自己的key
	 * 如果没有则动态生成key  
	 * @param joinPonit
	 * @param cacheFind
	 * @return
	 */
	public String getKey(ProceedingJoinPoint joinPonit,CacheFind cacheFind) {
		if(!StringUtils.isEmpty(cacheFind.key())) {
			//表示用户自己有key
			return cacheFind.key();
		}
		//1.获取对象的类路径  包名.类名
		String className=joinPonit.getSignature().getDeclaringTypeName();
		//2.获取方法名称
		String method=joinPonit.getSignature().getName();
		//3.动态获取第一个参数
		String firstArgs = joinPonit.getArgs()[0].toString();
		return className+"."+method+"::"+firstArgs;
	}
}
